#include "x_logstream.h"

#include <algorithm>
#include <cstdio>
namespace x_log
{

const char digits[] = "9876543210123456789";
enum {ZERO_POS = 9};
const char* zero = digits + ZERO_POS;

const char digitsHEX[] = "0123456789ABCDEF";

//integer to string conversion
template<typename T>
size_t int2string(char buf[], T value)
{
    T i = value;
    char* p = buf;
    do
    {
        int lsd = static_cast<int>(i % 10);
        i /= 10;
        *p++ = zero[lsd];
    }while (i != 0);

    if (value < 0)
    {
        *p++ = '-';
    }
    *p = '\0';
    std::reverse(buf, p);
    return p - buf;
}

size_t convertHex(char buf[], uintptr_t value)
{
    uintptr_t i = value;
    char* p = buf;
    do
    {
        int lsd = static_cast<int>(i % 16);
        i  /= 16;
        *p++ = digitsHEX[lsd];
    }while (i != 0);
    *p = '\0';
    std::reverse(buf, p);
    return p - buf;
}

template<typename T>
void CLogStream::formatInteger(T value)
{
    if (m_buffer.avail() >= kMaxNumericSize)
    {
        size_t len = int2string(m_buffer.current(), value);
        m_buffer.add(len);
    }
}

CLogStream& CLogStream::operator<< (short value)
{
    *this << static_cast<int>(value);
    return *this;
}

CLogStream& CLogStream::operator<< (unsigned short value)
{
    *this << static_cast<unsigned int>(value);
    return *this;
}

CLogStream& CLogStream::operator<< (int value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (unsigned int value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (long value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (unsigned long value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (long long value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (unsigned long long value)
{
    formatInteger(value);
    return *this;
}

CLogStream& CLogStream::operator<< (const void* p)
{
    auto v = reinterpret_cast<uintptr_t>(p);
    if (m_buffer.avail() > kMaxNumericSize)
    {
        char* buf = m_buffer.current();
        buf[0] = '0';
        buf[1] = 'x';
        size_t len = convertHex(buf + 2, v);
        m_buffer.add(len);
    }
    return *this;
}

CLogStream& CLogStream::operator<< (double value)
{
    if (m_buffer.avail() >= kMaxNumericSize)
    {
        int len = snprintf(m_buffer.current(), kMaxNumericSize, "%.12g", value);
        m_buffer.add(len);
    }
    return *this;
}



} //end namespace x_log